from typing_extensions import Annotated, List
from fastapi import (
    APIRouter, Depends, Path, HTTPException, status, Body
)
from fastapi.responses import FileResponse
from fastapi.encoders import jsonable_encoder

from core.database import db_session
from lib.common import get_paging_info
from lib.board_lib import insert_board_new, get_list_thumbnail
from api.v1.models.response import (
    response_401, response_403, response_404, response_422,
    response_429
)
from api.v1.dependencies.board import arange_file_data
from api.v1.models.board import (
    WriteModel, CommentModel, ResponseWriteModel, ResponseBoardModel,
    ResponseBoardListModel, ResponseNormalModel, ResponseCreateWriteModel,
    CommentUpdateModel
)
from api.v1.models.board import BoardPaginationRequest
from api.v1.service.board import (
    ListPostServiceAPI, ReadPostServiceAPI,
    CreatePostServiceAPI, UpdatePostServiceAPI, DownloadFileServiceAPI,
    DeletePostServiceAPI, CommentServiceAPI, DeleteCommentServiceAPI,
    MoveUpdateServiceAPI, ListDeleteServiceAPI
)
from service.board_file_service import BoardFileService
from service.ajax import AJAXService


router = APIRouter()

credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"},
)

#这个是get是获取数据，但是前提是先post数据；
@router.get("/{bo_table}/writes",
            summary="公告板查询",   #“查询公告栏”，
            responses={**response_401, **response_422}
            )
async def api_list_post(
    service: Annotated[ListPostServiceAPI, Depends(ListPostServiceAPI.async_init)],
    pagination: Annotated[BoardPaginationRequest, Depends()]  #这里类中包含了传入的查询参数  page  per_page
) -> ResponseBoardListModel:
    """
    返回公告栏信息；
    """
    per_page = service.get_board_per_page(pagination.per_page)

    writes = service.get_writes(
        with_files=True,
        page=pagination.page,
        per_page=pagination.per_page
    )
    total_records = service.get_total_count()
    paging_info = get_paging_info(
        pagination.page, per_page, total_records
    )
    content = {
        "total_records": total_records,
        "total_pages": paging_info["total_pages"],
        "categories": service.categories,
        "board": service.board,
        "notice_writes": service.get_notice_writes(),
        "writes": writes,
        "total_count": service.get_total_count(),
        "current_page": service.search_params['current_page'],
        "prev_spt": service.prev_spt,
        "next_spt": service.next_spt,
    }
    return jsonable_encoder(content) 
'''
因此，注释的返回类型和实际返回的 JSON 格式不完全相同，但它们之间是一种逻辑上的对应关系。
注释定义了预期的结构，而实际返回的内容可能经过了一些处理。这样可以更好地管理数据的验证和转换过程。
'''


@router.get("/{bo_table}/writes/{wr_id}",
            summary="公告板个人文章查询", #“查询留言板个别文章”，
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_read_post(
    db: db_session,
    service: Annotated[ReadPostServiceAPI, Depends(ReadPostServiceAPI.async_init)],
    ajax_service: Annotated[AJAXService, Depends(AJAXService.async_init)],
) -> ResponseWriteModel:
    """
    单独查看指定公告栏中的文章。
    """
    ajax_good_data = ajax_service.get_ajax_good_data(service.bo_table, service.write)
    thumbnail = get_list_thumbnail(
        service.request,
        service.board,
        service.write,
        service.gallery_width,
        service.gallery_height
    )
    content = jsonable_encoder(service.write)
    additional_content = jsonable_encoder({
        "thumbnail": thumbnail,
        "images": service.images,
        "normal_files": service.normal_files,
        "links": service.get_links(),
        "comments": service.get_comments(),
        "good": ajax_good_data["good"],
        "nogood": ajax_good_data["nogood"],
    })
    content.update(additional_content)
    service.validate_secret()
    service.validate_repeat_with_slowapi()
    service.block_read_comment()
    service.validate_read_level()
    service.check_scrap()
    service.check_is_good()
    db.commit()
    return content


@router.post("/{bo_table}/writes/{wr_id}",
            summary="公告板个人文章查询(秘密写作)", #“查看公告栏个别文章（秘密文章）
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_read_post(
    db: db_session,
    service: Annotated[ReadPostServiceAPI, Depends(ReadPostServiceAPI.async_init)],
    ajax_service: Annotated[AJAXService, Depends(AJAXService.async_init)],
    wr_password: str = Body(..., title="密码", description="秘密写入密码")
) -> ResponseWriteModel:
    """
    个人查询指定公告板上的秘密帖子.

    ### Request Body
    - **wr_password**: 开机自检密码
    """
    write_password = service.get_write_password()
    service.validate_read_wr_password(wr_password, write_password)
    ajax_good_data = ajax_service.get_ajax_good_data(service.bo_table, service.write)
    thumbnail = get_list_thumbnail(
        service.request,
        service.board,
        service.write,
        service.gallery_width,
        service.gallery_height
    )
    content = jsonable_encoder(service.write)
    additional_content = jsonable_encoder({
        "thumbnail": thumbnail,
        "images": service.images,
        "normal_files": service.normal_files,
        "links": service.get_links(),
        "comments": service.get_comments(),
        "good": ajax_good_data["good"],
        "nogood": ajax_good_data["nogood"],
    })
    content.update(additional_content)
    service.validate_repeat_with_slowapi()
    service.block_read_comment()
    service.check_scrap()
    service.check_is_good()
    db.commit()
    return content


@router.post("/{bo_table}/writes",
             summary="制作公告栏文章",  #制作公告栏文章
             responses={**response_401, **response_403,
                        **response_404, **response_422,
                        **response_429}
             )
async def api_create_post(
    db: db_session,
    service: Annotated[CreatePostServiceAPI, Depends(CreatePostServiceAPI.async_init)],
    wr_data: WriteModel,
) -> ResponseCreateWriteModel:
    """
在指定的公告栏中创建新文章。

### Request Body
-**wr_subject**：文章标题
-**wr_content**：文章内容
-**wr_name**：作者姓名（如果是非会员）
-**wr_password**：密码
-**wr_email**：作者邮件
-**wr_homepage**：作者主页
-**wr_link1***:链接1
-**wr_link2***:链接2
-**wr_option**：文章选项
-**html**：是否使用HTML
-**mail**：是否发送邮件
-**secret**：是否为秘密文章
-**ca_name“**：类别名称
-**notice**：是否有公告
-**parent_id**：父文章ID（如果是回复/评论）
-**wr_comment**：是否使用评论
    """
    service.validate_secret_board(wr_data.secret, wr_data.html, wr_data.mail)
    service.validate_post_content(wr_data.wr_subject)  
    service.validate_post_content(wr_data.wr_content)
    service.validate_write_level()
    service.arrange_data(wr_data, wr_data.secret, wr_data.html, wr_data.mail)
    service.validate_write_delay_with_slowapi()
    write = service.save_write(wr_data.parent_id, wr_data)
    insert_board_new(service.bo_table, write)
    service.add_point(write)
    parent_write = service.get_parent_post(wr_data.parent_id)
    service.send_write_mail_(write, parent_write)
    service.set_notice(write.wr_id, wr_data.notice)
    service.delete_cache()
    db.commit()
    return {"result": "created", "wr_id": write.wr_id}
    

@router.put("/{bo_table}/writes/{wr_id}",
            summary="公告板书写更正",
            responses={**response_401, **response_403,
                        **response_404, **response_422}
            )
async def api_update_post(
    db: db_session,
    service: Annotated[UpdatePostServiceAPI, Depends(UpdatePostServiceAPI.async_init)],
    wr_data: WriteModel,
) -> ResponseNormalModel:
    """
修改指定公告栏中的文章。

### Request Body
-**wr_subject**：文章标题
-**wr_content**：文章内容
-**wr_name**：作者姓名（如果是非会员）
-**wr_password**：密码
-**wr_email**：作者邮件
-**wr_homepage**：作者主页
-**wr_link1***:链接1
-**wr_link2***:链接2
-**wr_option**：文章选项
-**html**：是否使用HTML
-**mail**：是否发送邮件
-**secret**：是否为秘密文章
-**ca_name“**：类别名称
-**notice**：是否有公告
-**parent_id**：父文章ID（如果是回复/评论）
    """
    service.validate_restrict_comment_count()
    write = service.get_write(service.wr_id)
    service.validate_author(write, wr_data.wr_password)
    service.validate_secret_board(wr_data.secret, wr_data.html, wr_data.mail)
    service.validate_post_content(wr_data.wr_subject)
    service.validate_post_content(wr_data.wr_content)
    service.arrange_data(
        wr_data, wr_data.secret, wr_data.html, wr_data.mail, is_update=True
    )
    service.save_write(write, wr_data)
    service.set_notice(write.wr_id, wr_data.notice)
    service.update_children_category(wr_data)
    service.delete_cache()
    db.commit()
    return {"result": "updated"}


@router.delete("/{bo_table}/writes/{wr_id}",
                summary="删除公告板帖子",
                responses={**response_401, **response_403,
                           **response_404, **response_422}
               )
async def api_delete_post(
    service: Annotated[DeletePostServiceAPI, Depends(DeletePostServiceAPI.async_init)],
) -> ResponseNormalModel:
    """
    删除指定公告板上的帖子.
    """
    service.validate_level(with_session=False)
    service.validate_exists_reply()
    service.validate_exists_comment()
    service.delete_write()
    return {"result": "deleted"}


@router.post("/{bo_table}/writes/delete",
            summary="删除一批帖子",
            responses={**response_401, **response_403, **response_422}
            )
async def api_list_delete(
    service: Annotated[ListDeleteServiceAPI, Depends()],
    wr_ids: Annotated[List[int], Body(...)],
) -> ResponseNormalModel:
    """
批量删除帖子。

### Request Body
-**wr_ids**：要删除的帖子wr_id列表（例如[1,2,3]）
    """
    service.validate_admin_authority()
    service.delete_writes(wr_ids)
    return {"result": "deleted"}


@router.post("/{bo_table}/writes/{wr_id}/delete",
                summary="删除公告板非会员帖子",
                responses={**response_401, **response_403,
                           **response_404, **response_422}
               )
async def api_delete_post(
    service: Annotated[DeletePostServiceAPI, Depends(DeletePostServiceAPI.async_init)],
    wr_password: str = Body(..., title="密码", description="非会员书写密码")
) -> ResponseNormalModel:
    """
删除指定公告栏中的非会员文章。
    """
    service.validate_author(service.write, wr_password)
    service.validate_exists_reply()
    service.validate_exists_comment()
    service.delete_write()
    return {"result": "deleted"}


@router.get("/{bo_table}/{sw}",
            summary="复制帖子/移动列表查询",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_move_post(
    service: Annotated[MoveUpdateServiceAPI, Depends(MoveUpdateServiceAPI.async_init)],
) -> List[ResponseBoardModel]:
    """
返回可复制/移动帖子的公告栏列表。
sw:copy（复制帖子）或move（移动帖子）
    """
    service.validate_admin_authority()
    boards = service.get_admin_board_list()
    return boards


@router.post("/{bo_table}/{sw}",
            summary="复制/移动帖子",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_move_update(
    service: Annotated[MoveUpdateServiceAPI, Depends(MoveUpdateServiceAPI.async_init)],
    wr_ids: str = Body(..., title="书写id列表"),
    target_bo_tables: list = Body(..., title="复制/要移动的公告板表列表"),
) -> ResponseNormalModel:
    """
    复制/移动帖子。
    -同时修改Scrap、File等相关数据。

    ### Request Body
    -**sw**：copy（复制帖子）或move（移动帖子）
    -**wr_ids**：要复制/移动的帖子wr_id列表（例如“1,2,3”）
    -**target_bo_tables**：要复制/移动的公告栏列表（例如[“free”、“qa”]）
    """
    service.validate_admin_authority()
    origin_writes = service.get_origin_writes(wr_ids)
    service.move_copy_post(target_bo_tables, origin_writes)
    return {"result": f"发到所选公告板的帖子 {service.act} 我做到了.."}
 

@router.post("/{bo_table}/writes/{wr_id}/files",
            summary="上载文件",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_upload_file(
    service: Annotated[CreatePostServiceAPI, Depends(CreatePostServiceAPI.async_init)],
    file_service: Annotated[BoardFileService, Depends()],
    data: Annotated[dict, Depends(arange_file_data)],
    wr_id: int = Path(..., title="编写idi", description="编写idi"),
) -> ResponseNormalModel:
    """
上载文件。
-必须发送到multipart/form-data。
    """
    write = service.get_write(wr_id)
    service.upload_files(
        file_service, write, data["files"], data["file_contents"], data["file_dels"]
    )
    return {"result": "uploaded"}


@router.get("/{bo_table}/writes/{wr_id}/files/{bf_no}",
            summary="下载文件",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_download_file(
    service: Annotated[DownloadFileServiceAPI, Depends(DownloadFileServiceAPI.async_init)],
):
    """
    下载帖子的文件.

    - **bo_table**: post表名称
    - **wr_id**: 帖子名称
    - **bf_no**: 附加文件的顺序
    """
    service.validate_download_level()
    board_file = service.get_board_file()
    service.validate_point(board_file)
    return FileResponse(board_file.bf_file, filename=board_file.bf_source)


@router.post("/{bo_table}/writes/{wr_id}/comments",
            summary="写评论",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_create_comment(
    db: db_session,
    service: Annotated[CommentServiceAPI, Depends(CommentServiceAPI.async_init)],
    comment_data: CommentModel,
    bo_table: str = Path(..., title="公告板表名", description="公告板表名"),
    wr_id: int = Path(..., title="父母Glydy", description="父母Glydy"),
) -> ResponseNormalModel:
    """
注册评论
### Request Body
-**wr_content**：评论内容
-**wr_name**：作者姓名（如果是非会员）
-**wr_password**：密码
-**wr_option**：文章选项
-**comment_id**“留言ID（写回帖时留言id）
只输入wr_id-写评论
wr_id，输入comment_id-写回帖
    """
    parent_write = service.get_parent_post(wr_id, is_reply=False)
    service.validate_comment_level()
    service.validate_point()
    service.validate_post_content(comment_data.wr_content)
    service.validate_comment_password(comment_data.wr_password)
    service.validate_write_delay_with_slowapi()
    comment = service.save_comment(comment_data, parent_write)
    service.add_point(comment)
    service.send_write_mail_(comment, parent_write)
    insert_board_new(bo_table, comment)
    db.commit()
    return {"result": "created"}


@router.put("/{bo_table}/writes/{wr_id}/comments",
            summary="编辑评论",
            responses={**response_401, **response_403,
                       **response_404, **response_422}
            )
async def api_update_comment(
    db: db_session,
    service: Annotated[CommentServiceAPI, Depends(CommentServiceAPI.async_init)],
    comment_data: CommentUpdateModel,
) -> ResponseNormalModel:
    """
修改评论。

### Request Body
-**wr_content**：评论内容
-**wr_name**：作者姓名（如果是非会员）
-**wr_password**：密码
-**wr_option**：文章选项
-**comment_id**：评论ID（如果是对评论的修改，comment_id是对评论的id）
    """
    write_model = service.write_model
    service.get_parent_post(service.wr_id, is_reply=False)
    comment = db.get(write_model, comment_data.comment_id)
    if not comment:
        raise HTTPException(status_code=404, detail=f"{comment_data.comment_id} : 这是一个不存在的评论.")

    service.validate_author(comment, comment_data.wr_password)
    service.validate_post_content(comment_data.wr_content)
    comment.wr_content = service.get_cleaned_data(comment_data.wr_content)
    comment.wr_option = comment_data.wr_option or "html1"
    comment.wr_last = service.g5_instance.get_wr_last_now(write_model.__tablename__)
    db.commit()
    return {"result": "updated"}


@router.delete("/{bo_table}/writes/{wr_id}/comments/{comment_id}",
                summary="删除评论",
                responses={**response_401, **response_403,
                           **response_404, **response_422}
               )
async def api_delete_comment(
    service: Annotated[DeleteCommentServiceAPI, Depends(DeleteCommentServiceAPI.async_init)],
) -> ResponseNormalModel:
    """
    删除评论.
    """
    service.check_authority(with_session=False)
    service.delete_comment()
    return {"result": "deleted"}


@router.post("/{bo_table}/writes/{wr_id}/comments/{comment_id}/delete",
                summary="删除公告栏非会员评论",
                responses={**response_401, **response_403,
                           **response_404, **response_422}
               )
async def api_delete_post(
    service: Annotated[DeleteCommentServiceAPI, Depends(DeleteCommentServiceAPI.async_init)],
    wr_password: str = Body(..., title="密码", description="非会员评论密码")
) -> ResponseNormalModel:
    """
    删除指定论坛的非会员评论。
    """
    service.validate_author(service.write, wr_password)
    service.delete_comment()
    return {"result": "deleted"}